﻿using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Scripting;
using Microsoft.Scripting.Ast;
using Microsoft.Scripting.Runtime;
using IronTrishul.Compiler;

namespace IronTrishul.Compiler
{
    public class Parser
    {
        Dictionary<string, dynamic> localVariable;
        StringTokenizer tok;
        K konstant = new K();
        CompilerContext context;
        LambdaBuilder program;

        static MethodInfo consoleWriteLine = typeof(WebScript).GetMethod("WriteLine", new Type[] { typeof(string) });

        public static MethodInfo ConsoleWriteLine
        {
            get { return Parser.consoleWriteLine; }
            set { Parser.consoleWriteLine = value; }
        }

        Dictionary<string, dynamic> globalVariable = WindowProgram.GlobalVariable;
             
        public Parser(StringTokenizer tok)
        {
            this.tok = tok;
            localVariable  = new Dictionary<string, dynamic>();
        }
      

        //public Dictionary<string, object> GetVariable(string statementLine)
        public     List<Expression> GetStatements(CompilerContext context, LambdaBuilder program)
        {
            this.context = context;
            this.program = program;
            List<Expression> statements = new List<Expression>();
            Token firstToken = tok.Next();
            Expression lastExpression = GetStatement(firstToken);
            statements.Add(lastExpression);
           
            return statements; ;
        }
        /// <summary>
        /// This is going to be another project...
        /// So, will be doing minimal set of command....
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public Expression GetStatement(Token token)
        {
            Expression expr = null;
            while (token.Kind == TokenKind.WhiteSpace)
            {
                token = tok.Next();
            }

            //thats a begning of line...
            //Support one line primitive command line only
            if (token !=null)
            {
               
                string word = token.Value.ToUpper();
                switch (token.Kind)
                {

                    case TokenKind.EOF:

                        #region EOF
                        expr = Expression.Call(expr, consoleWriteLine, Utils.Constant(word));
                        break;
                        #endregion

                    case TokenKind.Word:

                        #region Word
                        if (konstant.SystemVerbs.ContainsKey(word))
                        {
                            if (word.ToUpper() == "PRINT")
                            {
                                expr = Expression.Call(expr, consoleWriteLine,

                                  GetStatement(tok.Next()) 
                                    
                                    );
                            }
                            else if (word.ToUpper() == "VAR" || word.ToUpper() == "SET")
                            {
                                Token nextToken = tok.Next();

                                while (nextToken.Kind == TokenKind.WhiteSpace)
                                {
                                    nextToken = tok.Next();
                                }
                                word = nextToken.Value;
                                expr = program.CreateGlobalVariable(word  , typeof(object));
                                if (!globalVariable.ContainsKey(word))
                                {
                                    //its a local variable..
                                    globalVariable.Add(word, "unassinged");
                                }
                                nextToken = tok.Next();

                                while (nextToken.Kind == TokenKind.WhiteSpace)
                                {
                                    nextToken = tok.Next();
                                }
                                word = nextToken.Value;
                                if (word == "=")
                                {
                                    expr = Expression.Assign(expr, GetStatement(nextToken));
                                }
                                else
                                {
                                    throw new Exception(string.Format("Expecting a variable...at line {0} at char {1}", token.Line, token.Column));
                                }
                            }
                            else
                            {
                                throw new Exception(string.Format("Expecting a variable...at line {0} at char {1}", token.Line, token.Column));
                            }
                        }
                        else
                        {
                            throw new Exception(string.Format("Expecting a variable...at line {0} at char {1}", token.Line, token.Column));
                        }
                        #endregion

                        break;
                    case TokenKind.QuotedString:

                        #region String Literal
                        expr = Expression.Constant(token.Value, typeof(string));
                       
                        #endregion

                        break;
                    case TokenKind.Number:

                        #region Number Literal
                        expr = Expression.Constant(token.Value, typeof(string));
                       
                        #endregion

                        break;
                    case TokenKind.Symbol:

                        #region All Symbols
                        if (token.Value == tok.SymbolChars[0].ToString())
                        {
                            expr = Expression.Assign(expr, GetStatement(token));
                        }
                        #endregion

                        break;
                    default:
                        expr = null;
                        break;
                }
            }
            return expr;
        }
            
    }
}
